//
//  asyn.h
//  asyn
//
//  Created by Eduardo Poyart on 2/6/12.
//  Copyright (c) 2012 Eduardo Poyart. All rights reserved.
//

#ifndef asyn_asyn_h
#define asyn_asyn_h

#include <string>
#include <vector>
#include <boost/asio.hpp>

class ANManager
{
public:
    ANManager();
    virtual ~ANManager();
    
    void update();

protected:
    boost::asio::io_service* _ioService;
    friend class ANTcpServer;
    friend class ANTcpClient;
};

class ANConnection
{
public:
    
    enum State
    {
        WAITING_TO_CONNECT,
        CONNECTED,
        CONNECTION_CLOSED
    };
    
    ANConnection(ANManager* manager):
        _manager(manager),
        _socket(0),
        _dataReady(false),
        _state(WAITING_TO_CONNECT) {}
    
    virtual ~ANConnection() {}
    
    virtual void send(const std::string& message) = 0;
    virtual bool isDataReady() const { return _dataReady; }
    virtual void receiveCopy(std::vector<char>& dest);
    virtual bool isConnected() const { return _state == CONNECTED; }

protected:
    virtual void read() = 0;
    
    ANManager* _manager;
    boost::asio::ip::tcp::socket* _socket;
    bool _dataReady;
    State _state;
    std::vector<char> _buffer;
};


class ANTcpServer: public ANConnection
{
public:
    
    ANTcpServer(ANManager* manager, int port, int bufferSize);
    virtual ~ANTcpServer() {}
    
    virtual void send(const std::string& message);
    
protected:
    virtual void read();
    void handleAccept(const boost::system::error_code& error);
    void handleWrite(const boost::system::error_code& error, size_t bytesTransferred);
    void handleRead(const boost::system::error_code& error, size_t bytesTransferred);

    boost::asio::ip::tcp::acceptor* _acceptor;
};

class ANTcpClient: public ANConnection
{
public:
    
    ANTcpClient(ANManager* manager, const std::string& host, const std::string& port, int bufferSize);
    virtual ~ANTcpClient() {}
    
    virtual void send(const std::string& message);
    
protected:
    virtual void read();
    void handleResolve(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator iterator);
    void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator iterator);
    void handleWrite(const boost::system::error_code& error, size_t bytesTransferred);
    void handleRead(const boost::system::error_code& error, size_t bytesTransferred);

    boost::asio::ip::tcp::resolver* _resolver;
};

#endif
